package com.md.config.database.sharding;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.orchestration.center.ConfigCenterRepository;
import org.apache.shardingsphere.orchestration.center.RegistryCenterRepository;
import org.apache.shardingsphere.orchestration.center.config.CenterConfiguration;
import org.apache.shardingsphere.orchestration.center.instance.NacosProperties;
import org.apache.shardingsphere.orchestration.center.instance.NacosPropertyKey;
import org.apache.shardingsphere.orchestration.center.listener.DataChangedEvent;
import org.apache.shardingsphere.orchestration.center.listener.DataChangedEventListener;
import org.apache.shardingsphere.orchestration.center.util.ConfigKeyUtils;

import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * @author 刘骄阳
 * 2022-03-16 11:15
 */
@Slf4j
public class MyRegistryCenterRepository implements RegistryCenterRepository, ConfigCenterRepository {

  private ConfigService configService;

  private NacosProperties nacosProperties;

  @Getter
  @Setter
  private Properties properties = new Properties();

  /**
   * 初始化nacos实例。
   *
   * @param config 配置中心的配置
   */
  @Override
  public void init(final CenterConfiguration config) {
    try {
      nacosProperties = new NacosProperties(properties);
      Properties property = new Properties();
      property.put(PropertyKeyConst.SERVER_ADDR, config.getServerLists());
      property.put(PropertyKeyConst.NAMESPACE, null == config.getNamespace() ? "" : config.getNamespace());
      configService = NacosFactory.createConfigService(property);
    } catch (final NacosException ex) {
      log.error("Init nacos config center exception for: {}", ex.toString());
    }
  }

  /**
   * Get data from nacos instance.
   *
   * @param key key of data
   * @return value of data
   */
  @Override
  public String get(final String key) {
    try {
      String dataId = ConfigKeyUtils.path2Key(key);
      String group = nacosProperties.getValue(NacosPropertyKey.GROUP);
      long timeoutMs = nacosProperties.getValue(NacosPropertyKey.TIMEOUT);
      return configService.getConfig(dataId, group, timeoutMs);
    } catch (final NacosException ex) {
      log.debug("Nacos get config value exception for: {}", ex.toString());
      return null;
    }
  }

  /**
   * Get node's sub-nodes list.
   *
   * @param key key of data
   * @return sub-nodes name list
   */
  @Override
  public List<String> getChildrenKeys(final String key) {
    return null;
  }

  /**
   * Persist data.
   *
   * @param key   key of data
   * @param value value of data
   */
  @Override
  public void persist(final String key, final String value) {
    try {
      String dataId = ConfigKeyUtils.path2Key(key);
      String group = nacosProperties.getValue(NacosPropertyKey.GROUP);
      configService.publishConfig(dataId, group, value);
    } catch (final NacosException ex) {
      log.debug("Nacos persist config exception for: {}", ex.toString());
    }
  }

  /**
   * Watch key or path of the config server.
   *
   * @param key                      key of data
   * @param dataChangedEventListener data changed event listener
   */
  @Override
  public void watch(final String key, final DataChangedEventListener dataChangedEventListener) {
    try {
      String dataId = ConfigKeyUtils.path2Key(key);
      String group = nacosProperties.getValue(NacosPropertyKey.GROUP);
      configService.addListener(dataId, group, new Listener() {

        @Override
        public Executor getExecutor() {
          return null;
        }

        @Override
        public void receiveConfigInfo(final String configInfo) {
          dataChangedEventListener.onChange(new DataChangedEvent(key, configInfo,
            DataChangedEvent.ChangedType.UPDATED));
        }
      });
    } catch (final NacosException ex) {
      log.debug("Nacos watch key exception for: {}", ex.toString());
    }
  }

  @Override
  public void close() {
    // TODO document why this method is empty
  }

  /**
   * Get algorithm type.
   *
   * @return type
   */
  @Override
  public String getType() {
    return "nacos";
  }

  /**
   * Persist ephemeral data.
   *
   * @param key   key of data
   * @param value value of data
   */
  @Override
  public void persistEphemeral(final String key, final String value) {
    log.info("key: " + key);
    log.info("value: " + value);

  }
}
